﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

using Utils.Buffer;

namespace Utils
{
    public static class StringHelper
    {
        private static readonly object objectLock = new object();

        //public static bool MatchAga(this string str, string keyword, params string[] keys)
        //{
        //    return true;
        //}

        static string Number = "0123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
        public static long UnShort(this string s)
        {
            long result = 0;
            if (!string.IsNullOrEmpty(s))
            {
                s = s.Trim();
                int l = s.Length;
                int m = Number.Length;
                for (int x = 0; x < l; x++)
                {
                    result += Number.IndexOf(s[l - 1 - x]) * (long)Math.Pow(m, x);
                }
            }
            return result;
        }

        public static string Short(this long val)
        {
            ulong n = (ulong)val;
            string result = string.Empty;
            uint l = (uint)Number.Length;
            while (n / l >= 1)
            {
                result = Number[(int)(n % l)] + result;
                n /= l;
            }
            result = Number[(int)n] + result;
            return result;
        }



        public static string Short(this Guid guid)
        {
            var array = guid.ToByteArray();
            return Short(array.CopyToNew(8).ToInt64()) + Short(array.CopyToNew(8, 8).ToInt64());

        }

        public static int FindInSet(this string strList, string ch)
        {
            if (strList == null) return -1;
            return new List<string>(strList.Split(',')).IndexOf(ch.ToString());
        }

        public static string IfNullOrEmpty(this string str, string defaultValue = "", string packageFormat = null)
        {
            return string.IsNullOrEmpty(str) ? defaultValue : (string.IsNullOrEmpty(packageFormat) ? str : string.Format(packageFormat, str));
        }

        public static bool IsSimplePassword(this string password)
        {
            if (password.Length < 6)
                return true;
            if (password.StartsWith("123456"))
                return true;
            if (password.EndsWith("654321"))
                return true;
            if (password.Distinct().Count() == 1)
                return true;
            return false;
        }
        public static string IfNullOrEmpty(this string str, Func<string> defaultValue)
        {
            return string.IsNullOrEmpty(str) ? defaultValue?.Invoke() : str;
        }



        /// <summary>
        /// UrlEncode Url编码
        /// </summary>
        /// <param name="str">待编码字符串</param>
        /// <param name="encoding">编码规则</param>
        /// <returns>编码后的字符串</returns>
        public static string UrlEncode(this string str, Encoding encoding)
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            return HttpUtility.UrlEncode(str, encoding);
        }
        /// <summary>
        /// UrlEncode Url编码,默认UTF-8编码
        /// </summary>
        /// <param name="str">待编码字符串</param>
        /// <returns>编码后的字符串</returns>
        public static string UrlEncode(this string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            return str.UrlEncode(Encoding.UTF8);
        }

        /// <summary>
        /// UrlDecode Url解码
        /// </summary>
        /// <param name="str">待解码字符串</param>
        /// <param name="encoding">解码规则</param>
        /// <returns>解码后的字符串</returns>
        public static string UrlDecode(this string str, Encoding encoding)
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            return HttpUtility.UrlDecode(str, encoding);
        }
        /// <summary>
        /// UrlDecode Url解码,默认UTF-8编码
        /// </summary>
        /// <param name="str">待解码字符串</param>
        /// <returns>解码后的字符串</returns>
        public static string UrlDecode(this string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            return str.UrlDecode(Encoding.UTF8);
        }

        public static IDictionary<string, string> LoadConfig(string configStr)
        {
            var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            if (configStr == null)
            {
                return dict;
            }
            var configs = configStr.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var config in configs)
            {
                int index = config.IndexOf(':');
                if (index >= 0)
                {
                    dict.Add(config[..index].Trim(), config[(index + 1)..].Trim());
                }
            }
            return dict;
        }
        public static string SubstringByte(this string text, int startIndex, int length)
        {
            return SubstringByte(text, startIndex, length, Encoding.UTF8);
        }

        public static string SubstringByte(this string text, int startIndex, int length, Encoding _encoding)
        {
            if (text == null) return null;
            byte[] bytes = _encoding.GetBytes(text);
            return _encoding.GetString(bytes, startIndex, Math.Min(bytes.Length - startIndex, length));
        }

        public static string FormatStr(this string str, params object[] args)
        {
            return string.Format(str, args);
        }

        #region 移除所有HTML标记
        /// <summary>
        /// 移除所有HTML标记
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string RemoveHtml(this string content)
        {
            if (string.IsNullOrEmpty(content))
            {
                return string.Empty;
            }
            const string regexstr = @"<[^>]*>";
            return Regex.Replace(content, regexstr, string.Empty, RegexOptions.IgnoreCase);
        }
        #endregion

        #region 移除不可见字符
        /// <summary>
        /// 移除不可见字符
        /// </summary>
        /// <param name="str">待操作字符串</param>
        /// <returns></returns>
        public static string RemoveInvisibleChar(this string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            var sb = new System.Text.StringBuilder(131);
            for (int i = 0; i < str.Length; i++)
            {
                int Unicode = str[i];
                if (Unicode >= 16)
                {
                    sb.Append(str[i].ToString());
                }
            }
            return sb.ToString();
        }
        #endregion

        #region 提取网页图片地址

        /// <summary>
        /// 提取网页图片地址
        /// </summary>
        /// <param name="sHtmlText"></param>
        /// <returns></returns>
        public static string[] GetHtmlImageUrlList(string sHtmlText)
        {
            if (string.IsNullOrEmpty(sHtmlText)) return new string[0];
            // 定义正则表达式用来匹配 img 标签   
            Regex regImg = new Regex(@"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase);

            // 搜索匹配的字符串   
            MatchCollection matches = regImg.Matches(sHtmlText);
            int i = 0;
            string[] sUrlList = new string[matches.Count];

            // 取得匹配项列表   
            foreach (Match match in matches)
                sUrlList[i++] = match.Groups["imgUrl"].Value;
            return sUrlList;
        }

        public static string[] GetContentByBrackets(string text)
        {
            if (string.IsNullOrEmpty(text)) return null;
            Regex reg = new Regex(@"(.*\()(?<content>.*)(\).*)", RegexOptions.Compiled);
            return reg.Matches(text).Where(a => a.Success).Select(a => a.Groups["content"].Value).ToArray();
        }

        #endregion

        #region 隐藏中间部分
        /// <summary>
        /// 隐藏
        /// </summary>
        /// <param name="str"></param>
        /// <param name="paddingChar"></param>
        /// <returns></returns>
        public static string HideMobile(this string str, char paddingChar = '*')
        {
            return HideSome(str, 3, 4, paddingChar);
        }
        /// <summary>
        /// 隐藏部分
        /// </summary>
        /// <param name="str"></param>
        /// <param name="splitChar"></param>
        /// <param name="paddingChar"></param>
        /// <returns></returns>
        public static string HideSome(this string str, char splitChar = ' ', char paddingChar = '*')
        {
            if (str.IsNullOrEmpty())
                return str;
            var strArray = str.Split(splitChar);

            for (int i = 1; i < Math.Max(strArray.Length - 1, 2); i++)
            {
                strArray[i] = "".PadRight(strArray[i].Length, paddingChar);
            }
            return string.Join(splitChar, strArray);
        }

        /// <summary>
        /// 隐藏部分
        /// </summary>
        /// <param name="str"></param>
        /// <param name="beginRetain"></param>
        /// <param name="endRetain"></param>
        /// <returns></returns>
        public static string HideSome(this string str, int beginRetain, int endRetain, char paddingChar = '*')
        {
            if (str.IsNullOrEmpty()) return str;
            string end = "";

            string begin = "";
            if (str.Length > endRetain + beginRetain)
            {
                end = str.Substring(str.Length - endRetain);
            }
            if (str.Length > beginRetain)
            {
                begin = str.Substring(0, beginRetain);
            }
            int paddingMiddle = str.Substring(0, str.Length - end.Length).Length;
            return begin.PadRight(paddingMiddle, paddingChar) + end;
        }

        /// <summary>
        /// 美化分隔
        /// </summary>
        /// <param name="str"></param>
        /// <param name="split"></param>
        /// <returns></returns>
        public static string BeautifySplit(this string str, int split = 4, bool reverse = false)
        {
            if (str.IsNullOrEmpty()) return str;
            if (split > 0)
            {
                if (reverse)
                {
                    str = new string(str.Reverse().ToArray());
                }
                string result = "";
                for (var i = 0; i < str.Length; i++)
                {
                    result += str[i];
                    if (i < str.Length - 3 && i % split == split - 1)
                        result += ' ';
                }
                if (reverse)
                {
                    result = new string(result.Reverse().ToArray());
                }
                return result;
            }
            return str;
        }


        /// <summary>
        /// 获得隐藏部分邮箱名称后的Email地址
        /// </summary>
        /// <param name="email">Email地址</param>
        /// <returns></returns>
        public static string HideEmail(string email)
        {
            if (string.IsNullOrEmpty(email))
            {
                return string.Empty;
            }
            if (email.IndexOf("@") > 0)
            {
                string name = email.Split('@')[0];
                string host = email.Split('@')[1];
                return string.Format("{0}***{1}@{2}", name.Substring(0, 1), name.Substring(name.Length - 1, 1), host);
            }
            else return email;
        }
        #endregion


        #region 静态私有变量
        /// <summary>
        /// 需要转义的字符正则
        /// </summary>
        static readonly Regex _transferredRule = new Regex(@"('|""|\\)", RegexOptions.Compiled);
        /// <summary>
        /// 数字
        /// </summary>
        static readonly string[] numArray = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
        /// <summary>
        /// 字母
        /// </summary>
        static readonly string[] letterArray = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "X" };
        /// <summary>
        /// 数字与字母混合
        /// </summary>
        static readonly string[] numberAndLetterArray = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "X" };
        #endregion

        #region 随机字符串类型


        /// <summary>
        /// 生成一个随机不重复的字符串，用于文件命名
        /// </summary>
        /// <returns>返回</returns>
        public static string RadomFileName()
        {
            return DateTime.Now.ToFileTime().ToString() + GetRandomNext(3);
        }

        public static string BuilderNo(string prefix)
        {
            lock (objectLock)
            {
                return prefix + DateTime.Now.FormatString("yyMMdd") + DateTime.Now.Ticks.ToString()[8..];
            }
        }

        public static string BuilderNo()
        {
            lock (objectLock)
            {
                return DateTime.Now.Ticks.ToString()[9..];
            }
        }
        /// <summary>
        /// 生成随机数
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        private static int GetRandomNext(int length)
        {
            Guid gu = Guid.NewGuid();
            string str = "";
            for (int i = 0; i < gu.ToString().Length; i++)
            {
                if (ValidatorHelper.IsInteger(gu.ToString()[i].ToString()))
                {
                    str += ((gu.ToString()[i]));
                }
            }
            int guid = int.Parse(str.Replace("-", "").Substring(0, length));
            if (!guid.ToString().Length.Equals(length))
                guid = GetRandomNext(length);
            return guid;
        }

        /// <summary>
        /// 获取随机字符串
        /// </summary>
        /// <param name="length">字符串长度</param>
        /// <param name="randCodeType">字符类型</param>
        /// <returns>返回生成的字符串</returns>
        public static string GetRandomCode(int length, RandCodeType randCodeType)
        {
            StringBuilder strb = new StringBuilder();
            long tick = DateTime.Now.Ticks;
            Random rnd = new Random((int)(tick & 0xffffffffL) | (int)(tick >> 32));
            int randcodeType = (int)randCodeType;

            for (int i = 0; i < length; i++)
            {
                switch (randcodeType)
                {
                    case 1:
                        strb.Append(numArray[rnd.Next(0, numArray.Length)]); break;
                    case 2:
                        strb.Append(letterArray[rnd.Next(0, letterArray.Length)]); break;
                    case 3:
                        strb.Append(numberAndLetterArray[rnd.Next(0, numberAndLetterArray.Length)]); break;
                }
            }

            return strb.ToString();
        }
        #endregion

        #region MD5加密

        /// <summary>
        /// 返回 System.String 对象进行MD5加密后的32字符十六进制格式字符串
        /// </summary>
        /// <param name="str">要加密的字符串</param>
        /// <param name="encode">编码</param>
        /// <returns>返回加密字符串</returns>
        public static string ToMD5(string str, Encoding encode)
        {
            if (str == null)
                throw new ArgumentNullException("str");


            using (MD5 md5 = MD5.Create())
            {
                byte[] bytes = md5.ComputeHash(encode.GetBytes(str));
                StringBuilder sb = new StringBuilder();
                foreach (var i in bytes)
                {
                    sb.Append(i.ToString("x2"));
                }
                return sb.ToString().ToUpper();
            }
        }

        public static string ToHashString(this byte[] bytes)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var i in bytes)
            {
                sb.Append(i.ToString("x2"));
            }
            return sb.ToString();
        }
        /// <summary>
        /// 返回 System.String 对象进行MD5加密后的32字符十六进制格式字符串,默认编码UTF8
        /// </summary>
        /// <param name="str">要加密的字符串</param>
        /// <returns>返回加密字符串</returns>
        public static string ToMD5(this string str)
        {
            return ToMD5(str, Encoding.UTF8);
        }

        /// <summary>
        /// 返回 System.String 对象进行MD5加密后的16字符十六进制格式字符串
        /// </summary>
        /// <param name="str">要加密的字符串</param>
        /// <param name="encode">编码</param>
        /// <returns>返回加密字符串</returns>
        public static string ToMD5Bit16(string str, Encoding encode)
        {
            return ToMD5(str, encode).Substring(8, 16);
        }

        /// <summary>
        /// 返回 System.String 对象进行MD5加密后的16字符十六进制格式字符串,默认编码GB2312
        /// </summary>
        /// <param name="str">要加密的字符串</param>
        /// <returns>返回加密字符串</returns>
        public static string ToMD5Bit16(this string str)
        {
            return ToMD5Bit16(str, Encoding.UTF8);
        }
        #endregion

        #region Base64加密
        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="str">待加密字符串</param>
        /// <param name="encode">字符编码，默认UTD-8</param>
        /// <returns></returns>
        public static string ToBase64Encode(this string str, string encode = "UTF-8")
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            return Convert.ToBase64String(Encoding.GetEncoding(encode).GetBytes(str));
        }
        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="str">待解密字符串</param>
        /// <param name="encode">字符编码，默认UTD-8</param>
        /// <returns></returns>
        public static string FromBase64String(this string str, string encode = "UTF-8")
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            return Encoding.GetEncoding(encode).GetString(Convert.FromBase64String(str));
        }
        #endregion


        public static string HumpToUnderline(string name)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var ch in name)
            {
                if (ValidatorHelper.Between(ch, 'A', 'Z'))
                {
                    if (sb.Length > 0)
                        sb.Append('_');
                    sb.Append((char)(ch + 0x20));
                }
                else
                {
                    sb.Append(ch);
                }
            }
            return sb.ToString();
        }

        public static string UnderlineToBigHump(string name)
        {
            StringBuilder sb = new StringBuilder();
            string[] names = name.Split('_');
            for (int i = 0; i < names.Length; i++)
            {
                sb.Append(names[i][0].ToString().ToUpper() + names[i][1..]);
            }
            return sb.ToString();
        }

        public static string UnderlineToSmallHump(string name)
        {
            StringBuilder sb = new StringBuilder();
            string[] names = name.Split('_');
            for (int i = 0; i < names.Length; i++)
            {
                if (i == 0)
                {
                    sb.Append(names[i][0].ToString().ToLower() + names[i][1..]);
                }
                else
                {
                    sb.Append(names[i][0].ToString().ToUpper() + names[i][1..]);
                }
            }
            return sb.ToString();
        }

        public static string ToFirstLower(string name)
        {
            if (name == null) return string.Empty;
            return name[..1].ToLower() + name[1..];
        }

        public static string ToFirstUpper(string name)
        {
            if (name == null) return string.Empty;
            return name[..1].ToUpper() + name[1..];
        }
    }
    /// <summary>
    /// 随机字符串类型
    /// </summary>
    [Flags]
    public enum RandCodeType
    {
        /// <summary>
        /// 仅数字
        /// </summary>
        NUMBER = 1,
        /// <summary>
        /// 字母
        /// </summary>
        LETTER = 2,

    }
}
